//// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
//// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
//// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
//// PARTICULAR PURPOSE.
////
//// Copyright (c) Microsoft Corporation. All rights reserved

#pragma once

// SoundEffect:
// This class plays a sound using XAudio2.  It uses a mastering voice provided 
// from the Audio class.  The sound data can be read from disk using the MediaReader
// class.

namespace
{
	class VoiceCallback : public IXAudio2VoiceCallback
	{
		public:
			VoiceCallback(bool* isPlayingHolder) :
				m_isPlayingHolder(isPlayingHolder)
			{
			}

			~VoiceCallback()
			{
				m_isPlayingHolder = nullptr;
			}

			//
			// Voice callbacks from IXAudio2VoiceCallback
			//
			STDMETHOD_(void, OnVoiceProcessingPassStart) (THIS_ UINT32 bytesRequired);
			STDMETHOD_(void, OnVoiceProcessingPassEnd) (THIS);
			STDMETHOD_(void, OnStreamEnd) (THIS);
			STDMETHOD_(void, OnBufferStart) (THIS_ void* bufferContext);
			STDMETHOD_(void, OnBufferEnd) (THIS_ void* bufferContext);
			STDMETHOD_(void, OnLoopEnd) (THIS_ void* bufferContext);
			STDMETHOD_(void, OnVoiceError) (THIS_ void* bufferContext, HRESULT error);

		private:
			bool* m_isPlayingHolder;
	};

	//
	// Callback handlers, only implement the buffer events for maintaining play state
	//
	void VoiceCallback::OnVoiceProcessingPassStart(UINT32 /*bytesRequired*/)
	{
	}
	void VoiceCallback::OnVoiceProcessingPassEnd()
	{
	}
	void VoiceCallback::OnStreamEnd()
	{
	}
	void VoiceCallback::OnBufferStart(void* /*bufferContext*/)
	{
		*m_isPlayingHolder = true;
	}
	void VoiceCallback::OnBufferEnd(void* /*bufferContext*/)
	{
		*m_isPlayingHolder = false;
	}
	void VoiceCallback::OnLoopEnd(void* /*bufferContext*/)
	{
	}
	void VoiceCallback::OnVoiceError(void* /*bufferContext*/, HRESULT /*error*/)
	{
	}
}

ref class SoundEffect
{
internal:
	SoundEffect();

	void Initialize(
		_In_ IXAudio2*              masteringEngine,
		_In_ WAVEFORMATEX*          sourceFormat,
		_In_ Platform::Array<byte>^ soundData
		);

	void Play(_In_ float volume, _In_ bool loop);
	void SetVolume(float volume);
	void Stop(bool waitUntilEnd);
	__forceinline bool IsPlaying() { return m_playing; }

protected private:
	bool                    m_audioAvailable;
	IXAudio2SourceVoice*    m_sourceVoice;
	Platform::Array<byte>^  m_soundData;

	std::shared_ptr<VoiceCallback> m_voiceCallback;
	bool					m_playing;
};
